"""
配置管理服务

提供应用程序配置的加载、验证和管理功能。
"""

import os
import yaml
import json
import re
import platform
from typing import Dict, Any, List
from pathlib import Path
import logging

from src.core.di import Singleton


@Singleton()
class ConfigService:
    """
    配置管理服务
    
    负责加载和管理应用程序配置。
    """
    
    def __init__(self):
        self.config: Dict[str, Any] = {}
        self.config_file_paths: List[str] = []
        self.logger = logging.getLogger(self.__class__.__name__)
        
        # 默认配置
        self._load_default_config()
    
    def _load_default_config(self) -> None:
        """加载默认配置"""
        # 检测平台并加载对应配置
        system = platform.system().lower()
        is_windows = system == "windows" or "microsoft" in platform.platform().lower()

        if is_windows:
            self._load_windows_config()
        else:
            self._load_unix_config()

    def _load_windows_config(self) -> None:
        """加载Windows专用配置"""
        # 获取用户目录
        user_home = os.path.expanduser("~")
        app_data_dir = os.path.join(user_home, "AppData", "Local", "MixVideo")

        self.config = {
            "app": {
                "name": "MixVideo",
                "version": "1.0.0",
                "debug": False,
                "log_level": "INFO"
            },
            "database": {
                "path": os.path.join(app_data_dir, "mixvideo.db"),
                "echo": False,
                "pool_size": 1,
                "max_overflow": 0,
                "pool_timeout": 30,
                "pool_recycle": 3600,
                "sqlite_options": {
                    "journal_mode": "DELETE",  # 避免WAL锁定问题
                    "synchronous": "OFF",      # 提高性能
                    "busy_timeout": 30000,     # 30秒超时
                    "cache_size": 10000,
                    "temp_store": "MEMORY",
                    "foreign_keys": "ON"
                }
            },
            "ffmpeg": {
                "binary_path": "ffmpeg",
                "ffprobe_path": "ffprobe",
                "max_concurrent_jobs": 3,
                "quality_presets": {
                    "low": {
                        "video_bitrate": "500k",
                        "audio_bitrate": "64k",
                        "scale": "640:360",
                        "crf": "28"
                    },
                    "medium": {
                        "video_bitrate": "1500k",
                        "audio_bitrate": "128k", 
                        "scale": "1280:720",
                        "crf": "23"
                    },
                    "high": {
                        "video_bitrate": "3000k",
                        "audio_bitrate": "192k",
                        "scale": "1920:1080", 
                        "crf": "18"
                    }
                }
            },
            "ai": {
                "gemini": {
                    "api_key": "",
                    "model": "gemini-pro-vision",
                    "temperature": 0.1,
                    "max_tokens": 1000,
                    "timeout": 30
                },
                "classification": {
                    "categories": ["AI素材", "产品展示", "产品使用", "模特试穿"],
                    "confidence_threshold": 0.8
                }
            },
            "storage": {
                "temp_dir": "./temp",
                "output_dir": "./output",
                "plugins_dir": "./plugins",
                "data_dir": "./data"
            },
            "workflow": {
                "max_execution_time": 3600,  # 1小时
                "auto_cleanup": True,
                "save_intermediate_results": False
            },
            "logging": {
                "level": "INFO",
                "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
                "file": "./logs/mixvideo.log",
                "max_size": "10MB",
                "backup_count": 5
            }
        }

    def _load_unix_config(self) -> None:
        """加载Unix/Linux专用配置"""
        self.config = {
            "app": {
                "name": "MixVideo",
                "version": "1.0.0",
                "debug": False,
                "log_level": "INFO"
            },
            "database": {
                "path": "./data/mixvideo.db",
                "echo": False,
                "pool_size": 5,
                "max_overflow": 10,
                "pool_timeout": 30,
                "pool_recycle": 3600,
                "sqlite_options": {
                    "journal_mode": "WAL",     # Unix下使用WAL模式
                    "synchronous": "NORMAL",   # 正常同步级别
                    "busy_timeout": 30000,
                    "cache_size": 10000,
                    "temp_store": "MEMORY",
                    "foreign_keys": "ON"
                }
            },
            "ffmpeg": {
                "binary_path": "ffmpeg",
                "ffprobe_path": "ffprobe",
                "max_concurrent_jobs": 3,
                "quality_presets": {
                    "low": {
                        "video_bitrate": "500k",
                        "audio_bitrate": "64k",
                        "scale": "640:480",
                        "crf": "28"
                    },
                    "medium": {
                        "video_bitrate": "1500k",
                        "audio_bitrate": "128k",
                        "scale": "1280:720",
                        "crf": "23"
                    },
                    "high": {
                        "video_bitrate": "3000k",
                        "audio_bitrate": "192k",
                        "scale": "1920:1080",
                        "crf": "18"
                    }
                }
            },
            "ai": {
                "gemini": {
                    "api_key": "",
                    "model": "gemini-pro-vision",
                    "temperature": 0.1,
                    "max_tokens": 1000,
                    "timeout": 30
                },
                "classification": {
                    "categories": ["AI素材", "产品展示", "产品使用", "模特试穿"],
                    "confidence_threshold": 0.8
                }
            },
            "storage": {
                "temp_dir": "./temp",
                "output_dir": "./output",
                "plugins_dir": "./plugins",
                "data_dir": "./data"
            },
            "workflow": {
                "max_execution_time": 3600,  # 1小时
                "auto_cleanup": True,
                "save_intermediate_results": False
            },
            "logging": {
                "level": "INFO",
                "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
                "file": "./logs/mixvideo.log",
                "max_size": "10MB",
                "backup_count": 5
            }
        }

    def load_from_file(self, config_path: str) -> None:
        """
        从文件加载配置
        
        Args:
            config_path: 配置文件路径
        """
        config_file = Path(config_path)
        
        if not config_file.exists():
            self.logger.warning(f"配置文件不存在: {config_path}")
            return
        
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                if config_file.suffix.lower() in ['.yaml', '.yml']:
                    file_config = yaml.safe_load(f)
                elif config_file.suffix.lower() == '.json':
                    file_config = json.load(f)
                else:
                    self.logger.error(f"不支持的配置文件格式: {config_file.suffix}")
                    return
            
            if file_config:
                # 处理环境变量替换
                file_config = self._substitute_env_variables(file_config)
                self._merge_config(file_config)
                self.config_file_paths.append(config_path)
                self.logger.info(f"配置文件加载成功: {config_path}")
        
        except Exception as e:
            self.logger.error(f"加载配置文件失败 {config_path}: {e}")
            raise
    
    def load_from_env(self, prefix: str = "MIXVIDEO_") -> None:
        """
        从环境变量加载配置
        
        Args:
            prefix: 环境变量前缀
        """
        env_config = {}
        
        for key, value in os.environ.items():
            if key.startswith(prefix):
                # 移除前缀并转换为小写
                config_key = key[len(prefix):].lower()
                
                # 处理嵌套键（用下划线分隔）
                keys = config_key.split('_')
                current = env_config
                
                for k in keys[:-1]:
                    if k not in current:
                        current[k] = {}
                    current = current[k]
                
                # 尝试转换值类型
                current[keys[-1]] = self._convert_env_value(value)
        
        if env_config:
            self._merge_config(env_config)
            self.logger.info(f"环境变量配置加载完成，前缀: {prefix}")
    
    def _convert_env_value(self, value: str) -> Any:
        """转换环境变量值类型"""
        # 布尔值
        if value.lower() in ['true', 'false']:
            return value.lower() == 'true'
        
        # 数字
        try:
            if '.' in value:
                return float(value)
            else:
                return int(value)
        except ValueError:
            pass
        
        # JSON
        if value.startswith('{') or value.startswith('['):
            try:
                return json.loads(value)
            except json.JSONDecodeError:
                pass
        
        # 字符串
        return value

    def _substitute_env_variables(self, config: Any) -> Any:
        """递归替换配置中的环境变量"""
        if isinstance(config, dict):
            return {key: self._substitute_env_variables(value) for key, value in config.items()}
        elif isinstance(config, list):
            return [self._substitute_env_variables(item) for item in config]
        elif isinstance(config, str):
            return self._substitute_string_env_variables(config)
        else:
            return config

    def _substitute_string_env_variables(self, text: str) -> str:
        """替换字符串中的环境变量"""
        # 支持 ${VAR_NAME} 和 $VAR_NAME 格式
        pattern = r'\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*)'

        def replace_var(match):
            var_name = match.group(1) or match.group(2)
            env_value = os.environ.get(var_name)

            if env_value is not None:
                return env_value
            else:
                # 如果环境变量不存在，保持原样并记录警告
                self.logger.warning(f"环境变量 {var_name} 未设置，保持原始值")
                return match.group(0)

        return re.sub(pattern, replace_var, text)

    def _merge_config(self, new_config: Dict[str, Any]) -> None:
        """合并配置"""
        self._deep_merge(self.config, new_config)
    
    def _deep_merge(self, base: Dict[str, Any], update: Dict[str, Any]) -> None:
        """深度合并字典"""
        for key, value in update.items():
            if key in base and isinstance(base[key], dict) and isinstance(value, dict):
                self._deep_merge(base[key], value)
            else:
                base[key] = value
    
    def get(self, key: str, default: Any = None) -> Any:
        """
        获取配置值
        
        Args:
            key: 配置键，支持点号分隔的嵌套键
            default: 默认值
        
        Returns:
            配置值
        """
        keys = key.split('.')
        current = self.config
        
        try:
            for k in keys:
                current = current[k]
            return current
        except (KeyError, TypeError):
            return default
    
    def set(self, key: str, value: Any) -> None:
        """
        设置配置值
        
        Args:
            key: 配置键，支持点号分隔的嵌套键
            value: 配置值
        """
        keys = key.split('.')
        current = self.config
        
        for k in keys[:-1]:
            if k not in current:
                current[k] = {}
            current = current[k]
        
        current[keys[-1]] = value
    
    def has(self, key: str) -> bool:
        """
        检查配置键是否存在
        
        Args:
            key: 配置键
        
        Returns:
            是否存在
        """
        return self.get(key) is not None
    
    def get_section(self, section: str) -> Dict[str, Any]:
        """
        获取配置段
        
        Args:
            section: 配置段名称
        
        Returns:
            配置段字典
        """
        return self.get(section, {})
    
    def save_to_file(self, config_path: str, format: str = "yaml") -> None:
        """
        保存配置到文件
        
        Args:
            config_path: 配置文件路径
            format: 文件格式 (yaml/json)
        """
        config_file = Path(config_path)
        config_file.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            with open(config_file, 'w', encoding='utf-8') as f:
                if format.lower() == 'yaml':
                    yaml.dump(self.config, f, default_flow_style=False, allow_unicode=True)
                elif format.lower() == 'json':
                    json.dump(self.config, f, indent=2, ensure_ascii=False)
                else:
                    raise ValueError(f"不支持的格式: {format}")
            
            self.logger.info(f"配置保存成功: {config_path}")
        
        except Exception as e:
            self.logger.error(f"保存配置失败 {config_path}: {e}")
            raise
    
    def validate_config(self) -> List[str]:
        """
        验证配置
        
        Returns:
            错误信息列表
        """
        errors = []
        
        # 验证FFmpeg配置
        ffmpeg_config = self.get_section("ffmpeg")
        if not ffmpeg_config.get("binary_path"):
            errors.append("FFmpeg可执行文件路径未配置")
        
        # 验证存储配置
        storage_config = self.get_section("storage")
        for dir_key in ["temp_dir", "output_dir", "data_dir"]:
            dir_path = storage_config.get(dir_key)
            if dir_path:
                try:
                    Path(dir_path).mkdir(parents=True, exist_ok=True)
                except Exception as e:
                    errors.append(f"无法创建目录 {dir_key}: {e}")
        
        # 验证AI配置（可选）
        ai_config = self.get_section("ai")
        gemini_config = ai_config.get("gemini", {})
        if not gemini_config.get("api_key"):
            # Gemini API密钥是可选的，只记录警告
            self.logger.warning("Gemini API密钥未配置，AI分类功能将不可用")
        
        return errors
    
    def get_all(self) -> Dict[str, Any]:
        """获取所有配置"""
        return self.config.copy()
    
    def reload(self) -> None:
        """重新加载配置"""
        self._load_default_config()
        
        for config_path in self.config_file_paths:
            try:
                self.load_from_file(config_path)
            except Exception as e:
                self.logger.error(f"重新加载配置文件失败 {config_path}: {e}")
        
        self.load_from_env()
        self.logger.info("配置重新加载完成")
    
    def create_directories(self) -> None:
        """创建配置中指定的目录"""
        storage_config = self.get_section("storage")
        
        for dir_key, dir_path in storage_config.items():
            if dir_key.endswith("_dir") and dir_path:
                try:
                    Path(dir_path).mkdir(parents=True, exist_ok=True)
                    self.logger.debug(f"目录创建成功: {dir_path}")
                except Exception as e:
                    self.logger.error(f"创建目录失败 {dir_path}: {e}")


# 创建全局配置服务实例
config_service = ConfigService()
